﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Reflection;

namespace ThreeByte.ActiveDeck.Data.UserResponse.Report {
    
    public abstract class IndividualUserData {

        protected static readonly XNamespace ns = Service.ServiceConfiguration.NAMESPACE;

        private static readonly Dictionary<string, Type> UserDataTypeLookup;

        static IndividualUserData() {
            UserDataTypeLookup = new Dictionary<string, Type>();

            //Collect UserData Types
            Assembly thisAssembly = Assembly.GetCallingAssembly();
            Type[] allTypes = thisAssembly.GetTypes();
            foreach(Type t in allTypes) {
                //Don't count the base
                if(!t.IsAbstract) {
                    //There exists some reference to this attribute
                    IndividualUserDataAttribute[] atts = (IndividualUserDataAttribute[])(t.GetCustomAttributes(typeof(IndividualUserDataAttribute), true));
                    if(atts.Length > 0) {
                        UserDataTypeLookup[atts.First().ShortTypeName] = t;  //This is a UserData object that we want to expose
                    }
                }
            }
        }

        protected IndividualUserData() {

        }

        public int Section {
            get;
            set;
        }

        public int Page {
            get;
            set;
        }

        public string Question {
            get;
            set;
        }

        private bool _isCorrect = false;
        public bool IsCorrect {
            get {
                return _isCorrect;   
            }
            set {
                _isCorrect = value;
            }
        }

        public bool HasCorrectAnswer {
            get;
            set;
        }

        public virtual XElement ToXml() {
            IndividualUserDataAttribute[] atts = (IndividualUserDataAttribute[])(this.GetType().GetCustomAttributes(typeof(IndividualUserDataAttribute), true));

            PropertyInfo answerPropertyInfo = this.GetType().GetProperty("Answer");
            PropertyInfo textAnswerPropertyInfo = this.GetType().GetProperty("TextAnswer");
            
            XElement node = new XElement(ns +  atts.First().ShortTypeName, new XAttribute("Section", Section), new XAttribute("Page", Page), new XAttribute("Question", Question == null ? "" : Question), 
                new XAttribute("Answer", answerPropertyInfo.GetValue(this, null).ToString()), new XAttribute("IsCorrect", IsCorrect.ToString()));

            if(textAnswerPropertyInfo != null) {
                node.SetAttributeValue("AnswerText", textAnswerPropertyInfo.GetValue(this, null).ToString());
            }

            return node;
        }

        public static IndividualUserData ParseXml(XElement node) {
            string typeString = node.Name.LocalName;

            IndividualUserData userData = (IndividualUserData)(UserDataTypeLookup[typeString].GetConstructor(new Type[] {typeof(XElement)})
                                .Invoke(new object[] { node }));

            return userData;
        }

        //Update the Answer values and return true if anything changed
        public abstract bool UpdateUserData(IndividualUserData newUserData);
    }
}
